
//
// Warnings
//

#pragma warning (disable: 4008) // division by zero
#pragma warning (disable: 4000) // use uninit var

//
// Typedefs
//

struct DummyInfo
{
	//int Id; // Index != Id
	int ParentIndex; // Points to the parent node
	//int ParentsCount; // Indicates how many nodes influence this one
};

struct DummyPropertiesDims
{
	// [0] - translation xyz num keys
	// [1] - rotation xyz num keys
	// [2] - scale xyz num keys
	int3x3 KeysCount;
};

struct DummyWorld
{
	float4x4 CtrlWorld; // Modifies meshs control points
	float4x4 NrmlWorld; // Modifies mesh vertex normal => N=(W^-1)'
};

//
// Globals
//

StructuredBuffer<DummyInfo> g_DummiesHierarchy : register (t0);
StructuredBuffer<DummyPropertiesDims> g_DummiesProps : register (t1);

//
// TODO: Simplify to single Texture2DArray<float4> per property (x`s are unused).
// or DONOT: Maybe the "exact interpolation" will be implemented.
//

Texture2DArray<float4> g_DummiesCachedTranslationVectors : register (t2);
Texture2DArray<float4> g_DummiesCachedRotationVectors : register (t3);
Texture2DArray<float4> g_DummiesCachedScaleVectors : register (t4);

Texture2DArray<float2> g_DummiesCachedTranslationJoints : register (t5);
Texture2DArray<float2> g_DummiesCachedRotationJoints : register (t6);
Texture2DArray<float2> g_DummiesCachedScaleJoints : register (t7);

RWStructuredBuffer<DummyWorld> g_DummiesLclWorlds : register (u0);

cbuffer PerFrame : register (cb0)
{
	float g_TimeSeconds; // Scene time
};

// 
// Functionality
//

#include "AnimCurveUtil_Interpolation.hlsli"
#include "AnimCurveUtil_Matrices.hlsli"

#define _Translation 0
#define _Rotation 1
#define _Scale 2

groupshared float3x3 gs_Transformation;
groupshared float4x4 gs_Translation;
groupshared float4x4 gs_Rotation;
groupshared float4x4 gs_Scale;

[numthreads(3, 3, 1)] void main( 
	in const uint3 groupId : SV_GroupID,
	in const uint3 groupThreadId : SV_GroupThreadID
	)
{
	const int dummyIndex = groupId.x;
	const int channelIndex = groupThreadId.y;
	const int propertyIndex = groupThreadId.x;
	const int numKeys = g_DummiesProps[dummyIndex].KeysCount[propertyIndex][propertyIndex];

	// Those values indicate whether this thread is active within thread group 
	// to avoid redundant calculations.

	const bool isActiveChannelThread = channelIndex == 0;
	const bool isActivePropertyThread = propertyIndex == 0;
	const bool isActiveThread = isActivePropertyThread && isActiveChannelThread;

	//
	// DEBUG >>>
	if (isActiveThread) 
	{
		printf("----------------------------------------------------");
		printf("DummyIndex = %d", dummyIndex);
		printf("----------------------------------------------------");
	}
	// DEBUG <<<
	//

	[call] switch (propertyIndex)
	{
	case 0: gs_Transformation[ 0 ][ channelIndex ] = CalculateTranslation( dummyIndex, channelIndex, 41.0f, numKeys ); break;
	case 1: gs_Transformation[ 1 ][ channelIndex ] = CalculateRotation( dummyIndex, channelIndex, 41.0f, numKeys ); break;
	case 2: gs_Transformation[ 2 ][ channelIndex ] = CalculateScale( dummyIndex, channelIndex, 41.0f, numKeys ); break;
	}

	GroupMemoryBarrierWithGroupSync(); 

	// Wait until all the group threads reach this sync point and perform all  
	// the calculations, then evaluate transformation matrices.

	if (isActiveChannelThread) [call] switch (propertyIndex)
	{
	case 0: gs_Translation = CreateMatrixTranslation( gs_Transformation[propertyIndex] ); break;
	case 1: gs_Rotation = CreateMatrixRotation( gs_Transformation[propertyIndex] ); break;
	case 2: gs_Scale = CreateMatrixScale( gs_Transformation[propertyIndex] ); break;
	};

	GroupMemoryBarrierWithGroupSync(); 
	
	// Wait until all the group threads reach this sync point and perform all 
	// the calculations, then evaluate local bone transformation matrix.
	
	if (isActiveThread)
	{
		//
		// DEBUG >>>
		printf("T  %f %f %f", gs_Transformation[ 0 ][ 0 ], gs_Transformation[ 0 ][ 1 ], gs_Transformation[ 0 ][ 2 ]);
		printf("R  %f %f %f", gs_Transformation[ 1 ][ 0 ], gs_Transformation[ 1 ][ 1 ], gs_Transformation[ 1 ][ 2 ]);
		printf("S  %f %f %f", gs_Transformation[ 2 ][ 0 ], gs_Transformation[ 2 ][ 1 ], gs_Transformation[ 2 ][ 2 ]);
		// DEBUG <<<
		//

		const float4x4 ctrlWorld =  _Calc_xform(gs_Translation, gs_Rotation, gs_Scale);
		const float4x4 normWorld = InvertTranspose(ctrlWorld);

		g_DummiesLclWorlds[dummyIndex].CtrlWorld = ctrlWorld;
		g_DummiesLclWorlds[dummyIndex].NrmlWorld = normWorld;
	}

}